package com.cloud.business.service.sys.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cloud.business.dao.sys.*;
import com.cloud.business.entity.sys.*;
import com.cloud.business.dao.sys.SysMenuMapper;
import com.cloud.business.entity.sys.SysMenu;
import com.cloud.business.model.commonvm.DeletePost;
import com.cloud.business.model.commonvm.ResultMsg;
import com.cloud.business.model.sys.sysmenuvm.SysMenuNavMetaModel;
import com.cloud.business.model.sys.sysmenuvm.SysMenuNavTreeVM;
import com.cloud.business.model.sys.sysmenuvm.SysMenuQueryModel;
import com.cloud.business.model.sys.sysmenuvm.SysMenuTreeVM;
import com.cloud.business.service.sys.ISysMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloud.core.common.ParamMap;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 系统菜单 服务实现类
 * </p>
 *
 * @author dh
 * @since 2020-03-21
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private SysPermissionMapper sysPermissionMapper;

    @Resource
    private SysRoleUserMapper sysRoleUserMapper;

    @Resource
    private SysRolePermissionMapper sysRolePermissionMapper;


    //region 获取分页列表

    /**
     * 获取分页列表
     *
     * @param SysMenuQueryModel
     * @param page
     * @param msg
     * @throws Exception
     */
    @Override
    public void getListByPage(SysMenuQueryModel SysMenuQueryModel, IPage<SysMenu> page, ResultMsg msg) throws Exception {
        QueryWrapper<SysMenu> sysMenuQueryWrapper = new QueryWrapper<>();
        sysMenuQueryWrapper.lambda().like(!StringUtils.isEmpty(SysMenuQueryModel.getQueryStr()), SysMenu::getName, SysMenuQueryModel.getQueryStr())
                .like(!StringUtils.isEmpty(SysMenuQueryModel.getQueryStr()), SysMenu::getCode, SysMenuQueryModel.getQueryStr());
        sysMenuMapper.selectPage(page, sysMenuQueryWrapper);
        msg.setMsg("获取成功");
    }
    //endregion

    //region 创建

    /**
     * 创建
     *
     * @param sysMenu
     * @param msg
     * @return
     * @throws Exception
     */
    @Override
    public Integer create(SysMenu sysMenu, ResultMsg msg) throws Exception {
        Date now = new Date();
        sysMenu.setCreateTime(now);
        sysMenu.setModificationTime(now);
        if (StringUtils.isEmpty(sysMenu.getCode())) {
            throw new Exception("code不能空");
        }
        // 校验code不可以重复
        checkCode(sysMenu);

        int count = sysMenuMapper.insert(sysMenu);
        //region 添加权限码
        if (count > 0) {
            for (int i = 0; i < 4; i++) {
                SysPermission sysPermission = new SysPermission();
                sysPermission.setCreateTime(now);
                sysPermission.setModificationTime(now);
                sysPermission.setCreateUserId(sysMenu.getCreateUserId());
                sysPermission.setModificationUserId(sysMenu.getCreateUserId());
                sysPermission.setService(sysMenu.getName());
                sysPermission.setMenuCode(sysMenu.getCode());
                sysPermission.setSort(i);

                switch (i) {
                    case 0: {
                        sysPermission.setPermission("Create");
                        sysPermission.setName("创建");
                        break;
                    }
                    case 1: {
                        sysPermission.setPermission("Edit");
                        sysPermission.setName("修改");
                        break;
                    }
                    case 2: {
                        sysPermission.setPermission("Delete");
                        sysPermission.setName("删除");
                        break;
                    }
                    case 3: {
                        sysPermission.setPermission("Query");
                        sysPermission.setName("查询");
                        break;
                    }
                    default:
                        break;
                }
                sysPermissionMapper.insert(sysPermission);
            }
        }
        //endregion
        msg.setMsg("创建成功");
        return sysMenu.getObjectId();
    }

    private void checkCode(SysMenu sysMenu) throws Exception {
        QueryWrapper<SysMenu> sysMenuQueryWrapper = new QueryWrapper<>();
        sysMenuQueryWrapper.lambda().eq(SysMenu::getCode, sysMenu.getCode());
        SysMenu sysRoleOld = sysMenuMapper.selectOne(sysMenuQueryWrapper);

        if (sysRoleOld != null) {
            throw new Exception("code重复");
        }
    }
    //endregion

    //region 更新

    /**
     * 更新
     *
     * @param sysMenu
     * @param msg
     * @return
     * @throws Exception
     */
    @Override
    public Integer update(SysMenu sysMenu, ResultMsg msg) throws Exception {

        if (StringUtils.isEmpty(sysMenu.getCode())) {
            throw new Exception("code不能空");
        }

        SysMenu sysMenuOld = sysMenuMapper.selectById(sysMenu.getObjectId());

        if (!sysMenuOld.getCode().equals(sysMenu.getCode())) {
            checkCode(sysMenu);
        }
        Date now = new Date();
        sysMenu.setModificationTime(now);
        int count = sysMenuMapper.updateById(sysMenu);
        msg.setMsg("更新成功");
        return sysMenu.getObjectId();
    }
    //endregion

    //region 获取单条

    /**
     * 获取单条
     *
     * @param operationId
     * @param objectId
     * @param msg
     * @return
     * @throws Exception
     */
    @Override
    public SysMenu getById(Integer operationId, Integer objectId, ResultMsg msg) throws Exception {
        SysMenu sysMenu = sysMenuMapper.selectById(objectId);
        msg.setMsg("获取成功");
        return sysMenu;
    }
    //endregion

    //region 批量删除

    /**
     * 批量删除
     *
     * @param deletePost
     * @param msg
     * @return
     * @throws Exception
     */
    @Override
    public int deleteByList(DeletePost deletePost, ResultMsg msg) throws Exception {
        msg.setMsg("删除成功");
        // TODO  删除菜单下对应的操作码 并且删除角色关联的操作码
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("object_id", deletePost.getKeyValues());
        List<SysMenu> sysMenus = sysMenuMapper.selectList(queryWrapper);
        List<String> stringList = sysMenus.stream().map(SysMenu::getCode).collect(Collectors.toList());
        int count = sysMenuMapper.deleteBatchIds(deletePost.getKeyValues());
        if (count <= 0) {
            throw new Exception("删除失败");
        }
        sysPermissionMapper.deleteCode(stringList);
        return count;
    }
    //endregion

    //region 获取模块树

    /**
     * 获取模块树
     *
     * @param operationId
     * @return
     */
    @Override
    public List<SysMenuTreeVM> getMenuTree(Integer operationId) {

        List<SysMenuTreeVM> sysMenuTreeVMList = new ArrayList<>();
        QueryWrapper<SysMenu> sysMenuQueryWrapper = new QueryWrapper<>();
        sysMenuQueryWrapper.lambda()
                .eq(SysMenu::getPid, 0)
                .orderByAsc(SysMenu::getSort)
                .orderByDesc(SysMenu::getCreateTime);

        return getSysMenuTreeVMS(operationId, sysMenuTreeVMList, sysMenuQueryWrapper);
    }

    private List<SysMenuTreeVM> getSysMenuTreeVMS(Integer operationId, List<SysMenuTreeVM> sysMenuTreeVMList, QueryWrapper<SysMenu> sysMenuQueryWrapper) {
        List<SysMenu> sysMenuList = sysMenuMapper.selectList(sysMenuQueryWrapper);
        sysMenuList.forEach(sysMenu -> {
            SysMenuTreeVM sysMenuTreeVM = new SysMenuTreeVM();
            sysMenuTreeVM.setId(sysMenu.getObjectId());
            sysMenuTreeVM.setName(sysMenu.getName());
            sysMenuTreeVM.setIcon(sysMenu.getIcon());
            sysMenuTreeVM.setPath(sysMenu.getPath());
            sysMenuTreeVM.setPid(sysMenu.getPid());
            sysMenuTreeVM.setCode(sysMenu.getCode());
            sysMenuTreeVM.setSort(sysMenu.getSort());
            sysMenuTreeVM.setDescription(sysMenu.getDescription());
            sysMenuTreeVM.setEnable(sysMenu.getIsEnable());
            List<SysMenuTreeVM> children = GetMenuChildren(operationId, sysMenu.getObjectId());
            sysMenuTreeVM.setChildren(children);
            sysMenuTreeVMList.add(sysMenuTreeVM);
        });

        return sysMenuTreeVMList;
    }

    private List<SysMenuTreeVM> GetMenuChildren(Integer operationId, Integer pid) {

        List<SysMenuTreeVM> sysMenuTreeVMList = new ArrayList<>();
        QueryWrapper<SysMenu> sysMenuQueryWrapper = new QueryWrapper<>();
        sysMenuQueryWrapper.lambda().eq(SysMenu::getPid, pid)
                .orderByAsc(SysMenu::getSort)
                .orderByDesc(SysMenu::getCreateTime);

        return getSysMenuTreeVMS(operationId, sysMenuTreeVMList, sysMenuQueryWrapper);
    }
    //endregion

    //region 获取用户模块树

    /**
     * 获取用户模块树
     *
     * @param operationId
     * @return
     */
    @Override
    public List<SysMenuNavTreeVM> getUserMenuTree(Integer operationId) {

        List<SysMenuNavTreeVM> sysMenuNavTreeVMList = new ArrayList<>();
        ParamMap paramMap = new ParamMap();
        paramMap.put("userId", operationId);
        paramMap.put("pid", 0);

        return getSysMenuNavTreeVMS(operationId, sysMenuNavTreeVMList, paramMap);
    }

    private List<SysMenuNavTreeVM> getSysMenuNavTreeVMS(Integer operationId, List<SysMenuNavTreeVM> sysMenuNavTreeVMList, ParamMap paramMap) {
        List<SysMenu> sysMenuList = sysMenuMapper.getUserAllMenus(paramMap);
        if (sysMenuList.size() > 0) {
            for (SysMenu sysMenu : sysMenuList
            ) {
                SysMenuNavTreeVM sysMenuNavTreeVM = new SysMenuNavTreeVM();
                sysMenuNavTreeVM.setId(sysMenu.getObjectId());
                sysMenuNavTreeVM.setPid(sysMenu.getPid());
                sysMenuNavTreeVM.setName(sysMenu.getName());
                sysMenuNavTreeVM.setPath(sysMenu.getPath());
                sysMenuNavTreeVM.setSort(sysMenu.getSort());
                sysMenuNavTreeVM.setRedirect(sysMenu.getRedirect());

                SysMenuNavMetaModel sysMenuNavMetaModel = new SysMenuNavMetaModel();
                sysMenuNavMetaModel.setIcon(sysMenu.getIcon());
                sysMenuNavMetaModel.setTitle(sysMenu.getName());
                sysMenuNavMetaModel.setRoute(sysMenu.getDescription());

                sysMenuNavTreeVM.setMeta(sysMenuNavMetaModel);

                List<String> KeyCodes = GetPermissionByUM(operationId, sysMenu.getObjectId());

                sysMenuNavTreeVM.setKeyCodes(KeyCodes);

                List<SysMenuNavTreeVM> children = GetUserMenuTreeChildren(operationId, sysMenu.getObjectId());
                sysMenuNavTreeVM.setChildren(children);
                sysMenuNavTreeVMList.add(sysMenuNavTreeVM);
            }
        }

        return sysMenuNavTreeVMList;
    }

    private List<SysMenuNavTreeVM> GetUserMenuTreeChildren(Integer operationId, long pid) {

        List<SysMenuNavTreeVM> sysMenuNavTreeVMList = new ArrayList<>();
        ParamMap paramMap = new ParamMap();
        paramMap.put("userId", operationId);
        paramMap.put("pid", pid);

        return getSysMenuNavTreeVMS(operationId, sysMenuNavTreeVMList, paramMap);
    }
    //endregion

    //region 根据用户和菜单获取操作码

    /**
     * 根据用户和菜单获取操作码
     *
     * @param operationId
     * @param menuId
     * @return
     */
    private List<String> GetPermissionByUM(Integer operationId, Integer menuId) {

        List<String> KeyCodes = new ArrayList<>();

        List<Integer> RoleIds = new ArrayList<>();
        QueryWrapper<SysRoleUser> sysRoleUserQueryWrapper = new QueryWrapper<>();
        sysRoleUserQueryWrapper.lambda()
                .select(SysRoleUser::getRoleId)
                .eq(SysRoleUser::getUserId, operationId);
        List<Object> roleUserIdsObj = sysRoleUserMapper.selectObjs(sysRoleUserQueryWrapper);
        roleUserIdsObj.forEach(roleUser -> {
            RoleIds.add((Integer.parseInt(roleUser.toString())));
        });

        for (Integer roleId : RoleIds
        ) {
            List<String> permissonList = GetRolePermissions(operationId, roleId, menuId);

            if (permissonList.size() > 0) {
                if (KeyCodes.size() > 0) {

                    KeyCodes = Stream.of(KeyCodes, permissonList)
                            .flatMap(Collection::stream)
                            .distinct()
                            .collect(Collectors.toList());
                } else {
                    KeyCodes = new ArrayList<>(permissonList);
                }
            }
        }
        return KeyCodes;
    }
    //endregion

    //region 获取用户角色权限

    /**
     * 获取用户角色权限
     *
     * @param operationId
     * @param roleId
     * @param menuId
     * @return
     */
    private List<String> GetRolePermissions(Integer operationId, Integer roleId, Integer menuId) {


        List<String> sysPermissionVMList = new ArrayList<>();

        List<Integer> permissionIds = new ArrayList<>();
        QueryWrapper<SysRolePermission> sysRolePermissionQueryWrapper = new QueryWrapper<>();
        sysRolePermissionQueryWrapper.lambda()
                .select(SysRolePermission::getPermissionId)
                .eq(SysRolePermission::getRoleId, roleId);
        List<Object> roleUserIdsObj = sysRolePermissionMapper.selectObjs(sysRolePermissionQueryWrapper);
        roleUserIdsObj.forEach(roleUser -> {
            permissionIds.add((Integer.parseInt(roleUser.toString())));
        });

        SysMenu sysMenu = sysMenuMapper.selectById(menuId);

        QueryWrapper<SysPermission> sysPermissionQueryWrapper = new QueryWrapper<>();
        sysPermissionQueryWrapper.lambda()
                .eq(SysPermission::getMenuCode, sysMenu.getCode())
                .in(SysPermission::getObjectId, permissionIds.stream().distinct().collect(Collectors.toList()));

        List<SysPermission> sysPermissionList = sysPermissionMapper.selectList(sysPermissionQueryWrapper);

        for (SysPermission sysPermission : sysPermissionList
        ) {
            sysPermissionVMList.add(sysPermission.getPermission());
        }
        return sysPermissionVMList;
    }
    //endregion
}
